#pragma once

#include <pthread.h>
#include <functional>
#include "Protocal.hpp"
#include "Sock.hpp"
#include "Log.hpp"
#include "Util.hpp"

using namespace protocal_ns;

using func_t = std::function<Reponse(const Request &request)>;

class ns_server;

class ThreadData
{
public:
    ThreadData(int sock, std::string clientIp, uint16_t clientPort, ns_server *server)
        : _sock(sock), _clientIp(clientIp), _clientPort(clientPort), _server(server)
    {
    }

    ~ThreadData()
    {
    }

public:
    int _sock;
    std::string _clientIp;
    uint16_t _clientPort;
    ns_server *_server;
};

class ns_server
{
public:
    ns_server(uint16_t serverPort, func_t func)
        : _serverPort(serverPort), _func(func)
    {
    }

    void InitServer()
    {
        _listenSock.Socket();
        _listenSock.Bind(_serverPort);
        _listenSock.Listen();
    }

    void start()
    {
        while (true)
        {
            std::string clientIp;
            uint16_t clientPort;
            int sock = _listenSock.Accept(&clientIp, &clientPort);
            if (sock > 0)
            {
                LogMessage(Debug, "%s-%d accept success", clientIp.c_str(), clientPort);
            }

            ThreadData *data = new ThreadData(sock, clientIp, clientPort, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, ThreadRoutine, data);
        }
    }

    static void *ThreadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = static_cast<ThreadData *>(args);
        data->_server->service(data->_sock, data->_clientIp, data->_clientPort);
        LogMessage(Debug, "%s-%d exit", data->_clientIp.c_str(), data->_clientPort);
        delete data;
        return nullptr;
    }

    void service(int sock, std::string clientIp, uint16_t clientPort)
    {
        std::string inbuffer;
        while (true)
        {
            std::string package;
            int n = ReadPackage(sock, inbuffer, &package);
            if (n < 0)
                break;
            else if (n == 0)
                continue;
            else
            {
                // 1.去除报头
                std::string res = RemoveHeader(package, n);

                // 2.反序列化
                Request req;
                req.DeSerialize(res);

                // 3.业务逻辑
                Reponse Res = _func(req);

                // 4.序列化
                std::string result;
                Res.Serialize(&result);

                // 5.添加报头
                result = AddHeader(result);

                // 6.发送
                send(sock, result.c_str(), result.size(), 0);//注意这里用的是sock,而不是_listenSock.Fd()
            }
        }
    }

    ~ns_server()
    {
    }

private:
    Sock _listenSock;
    uint16_t _serverPort;
    func_t _func;
};
